<?php

namespace mbilling\BillingBundle\Services;
use Doctrine\ORM\EntityManager;
use mbilling\BillingBundle\Model\DomainsZonesModel;
use mbilling\BillingBundle\Model\DomainsStopModel;
use mbilling\BillingBundle\Model\DomainsModel;
//use mbilling\BillingBundle\Model\DomainsZonesGatewaysModel;

class CheckDomain
{
    protected $em;
    protected $idna;
    var $domain		 = "";
    var $my_whois_server = "";
    var $last_error	 = null;
    var $servers	 = array();

    public function __construct(EntityManager $entityManager, $idna)
    {
        $this->em = $entityManager;
        $this->idna = $idna;
    }
    /**
    * Init new domain name
    * @param	string	$sDomainName
    *
    */
    public function init( $sDomainName )
    {
        $this->initServers();
        /**
         * Не ascii домен?
         *
         */
        if( 0 !== preg_match( '/[^a-z]+/i', $sDomainName ) )
        {
            $sDomainName = $this->convertToPunycode( $sDomainName );
        }
        $this->domain          = $sDomainName;
        $this->my_whois_server = $this->get_whois_server();
        $this->min_length      = $this->get_min_length();
        $this->last_error      = null;
        $this->sError          = null;
    }

    function _getLastError()
    {
        return $this->sError;
    }

    function convertToPunycode( $s )
    {
        return $this->idna->encode( $s );
    }

    function convertFromPunycode( $s )
    {
        return $this->idna->decode( $s );
    }
    /**
    * Returns the whois data of the domain
    * @return string $whoisdata Whois data as string
    * @desc Returns the whois data of the domain
    */
    function info()
    {
        if( false === $this->is_valid() )
        {
            $this->setError( 'DOMAIN_BAD_NAME' );
            return null;
        }

        $tldname = $this->get_tld();
        if( null === $tldname )
        {
            $this->setError( 'DOMAIN_BAD_NAME' );
            return null;
        }

        $domainname = $this->get_domain();
        if( null !== $this->min_length &&
            strlen( $domainname ) < $this->min_length )
        {
            return DOMAIN_NAME_TO_LESS;
        }

        $whois_server	= $this->my_whois_server;
        // If tldname have been found
        if( null === $whois_server )
        {
            $this->last_error = 'No whois server for this tld in list!';
            return null;
        }

        // Getting whois information

        $fp	= @fsockopen( $whois_server, 43 );
        if( false === $fp )
        {
            $this->last_error = 'Can\'t connect to whois server!';
            return null;
        }

        fputs( $fp, $domainname . '.' . $tldname . "\r\n" );
        // Getting string
        $s = '';
        while( !feof( $fp ) )
            $s .= fgets( $fp, 128 );
        fclose( $fp );

        return $s;
    }

    /**
    * Returns the whois data of the domain in HTML format
    * @return string $whoisdata Whois data as string in HTML
    * @desc Returns the whois data of the domain  in HTML format
    */
    function html_info()
    {
	return nl2br( $this->info() );
    }

    /**
    * Returns name of the whois server of the tld
    * @return string $server the whois servers hostname
    * @desc Returns name of the whois server of the tld
    */
    function get_whois_server()
    {
        $mTLD	= $this->get_tld();
        if( null === $mTLD )
            return null;

        for( $i = 0, $iCount = count( $this->servers ); $i < $iCount; $i++ ) {
            $p	=& $this->servers[ $i ];
            if( $mTLD === $p[ 0 ] )
                return $p[ 1 ];
        }
        return null;
    }

    protected function get_min_length()
    {
        $mTLD	= $this->get_tld();

        if( null === $mTLD )
        {
            return null;
        }
        for( $i = 0, $iCount = count( $this->servers ); $i < $iCount; $i++ )
        {
            $p	=& $this->servers[ $i ];

            if( $mTLD === $p[ 0 ] )
            {
                    return false === isset( $p[ 3 ] ) ? null : $p[ 3 ];
            }
        }
        return null;
    }

    /**
    * Returns the tld of the domain without domain name
    * @return string $tldname the tlds name without domain name
    * @desc Returns the tld of the domain without domain name
    */
    function get_tld()
    {
        // Splitting domainname
        $domain	= explode( '.', $this->domain );

        if( count( $domain ) < 2 )
            return null;
        if(count($domain)>2)
        {
            $domainname=$domain[0];
            for($i=1;$i<count($domain);$i++)
            {
                    if($i==1)
                    {
                        $tldname=$domain[$i];
                    }
                    else
                    {
                        $tldname.=".".$domain[$i];
                    }
            }
        }
        else
        {
            $domainname=$domain[0];
            $tldname=$domain[1];
        }
        return $tldname;
    }

    /**
    * Returns all tlds which are supported by the class
    * @return array $tlds all tlds as array
    * @desc Returns all tlds which are supported by the class
    */
    function get_tlds()
    {
        $tlds="";
        for($i=0;$i<count($this->servers);$i++)
        {
            $tlds[$i]=$this->servers[$i][0];
        }
        return $tlds;
    }

    /**
    * Returns the name of the domain without tld
    * @return string $domain the domains name without tld name
    * @desc Returns the name of the domain without tld
    */
    function get_domain()
    {
        // Splitting domainname
        $domain	= explode( '.', $this->domain );
        return $domain[0];
    }

    /**
    * Returns the string which will be returned by the whois server of the tld if a domain is avalable
    * @return string $notfound  the string which will be returned by the whois server of the tld if a domain is avalable
    * @desc Returns the string which will be returned by the whois server of the tld if a domain is avalable
    */
    function get_notfound_string()
    {
        $tldname=$this->get_tld();
//	$zone=GetZoneByZone($tldname);
//	if ($zone->notfoundstring) { return $zone->notfoundstring; }
        for($i=0;$i<count($this->servers);$i++)
        {
            if($this->servers[$i][0]==$tldname){
                $notfound=$this->servers[$i][2];
                    return $notfound;
            }
        }
    }

    /**
    * Returns if the domain is available for registering
    * @return boolean $is_available Returns true if domain is available and false if domain isn't available
    * @desc Returns if the domain is available for registering
    */
    public function is_available()
    {
        if( null === $this->my_whois_server )
        {
            $this->setError( 'DOMAIN_UNKNOWN_WHOIS_SERVER' );
            return true;
        }
        // Gets the entire WHOIS query from registrar
        if( null === $mWhois = $this->info() )
        {
            return $this->getError();
        }
        if( null === $mWhois )
        {
            return false;
        }

        // Gets 3rd item from array
        $sNotFound = $this->get_notfound_string();
        //Replace whitespace with single space
        $sWhois = preg_replace( '/\s+/', ' ', $mWhois );
        $a	= explode( ':', $sNotFound );

        if( 'MAXCHARS' === $a[ 0 ] )
        {
            $b	= strlen( $sWhois ) <= $a[ 1 ] ? true : false;
        }
        else
        {
            $b	= preg_match( '/' . $sNotFound . '/i', $sWhois ) ? false : true;
        }
        if( true === $b )
        {
            $this->setError( 'DOMAIN_ALREADY_EXISTS' );
            return true;
        }
        return false;
    }

    /**
    * Returns if the domain's zone is available on the hosting server
    * @return boolean $is_available_zone Returns true if domain's zone is available and false if domain's zone isn't available on hosting server
    * @desc Returns if the domain's zone is available on hosting server
    */
    public function is_available_zone()
    {
        foreach($this->servers as $server)
        {
            if ( $server[0] ==  $this->get_tld())
                return true;
            /*else
            if (( $this->get_tld() == 'xn--p1ai') && ($server[0] == 'рф'))
                return true;*/
        }
        return false;
    }
    
    /**
    * Returns if the domain name is valid
    * @return boolean $is_valid Returns 1 if domain is valid and 0 if domain isn't valid
    * @desc Returns if the domain name is valid
    */
    function is_valid()
    {
        $m = preg_match( '/^([a-z0-9]([-a-z0-9]*[a-z0-9])?\.)+((a[cdefgilmnoqrstuwxz]|aero|arpa)|(b[abdefghijmnorstvwyz]|biz)|(c[acdfghiklmnorsuvxyz]|cat|com|coop)|d[ejkmoz]|(e[ceghrstu]|edu)|f[ijkmor]|(g[abdefghilmnpqrstuwy]|gov)|h[kmnrtu]|(i[delmnoqrst]|info|int)|(j[emop]|jobs)|k[eghimnprwyz]|l[abcikrstuvy]|(m[acdghklmnopqrstuvwxyz]|mil|mobi|museum)|(n[acefgilopruz]|name|net)|(om|org)|(p[aefghklmnrstwy]|pro)|qa|r[eouw]|s[abcdeghijklmnortuvyz]|(t[cdfghjklmnoprtvwz]|travel)|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw]|xn--p1ai)$/', $this->domain );
        return 0 !== $m;
    }

    protected function setError( $s )
    {
        $this->sError	= $s;
    }

    public function getError()
    {
        return $this->sError;
    }

    public function getDomain()
    {
        return $this->domain;
    }

    public function sum($n1, $n2) 
    {
        return $n1 + $n2;
    }

    public function is_not_regOnServer()
    {
        $domain_model = new DomainsModel($this->em);
        if ($domain_model->checkDomain($this->getDomain()))
            return false;
        else
            return true;
    }
    
    public function is_not_stopDomain()
    {
        $domainStop_model = new DomainsStopModel($this->em);
        $domainStop = $domainStop_model->findByDomainName($this->getDomain());
        if (isset($domainStop))
            return false;
        else
            return true;
    }
    
    public function initServers()
    {
        $zone_model = new DomainsZonesModel($this->em);
        //$zoneGateway_model = new DomainsZonesGatewaysModel($this->em);
        $zones = $zone_model->findAll();
        foreach ($zones as $zone)
        {
            //$gateway = $zoneGateway_model->findByPK($zone->getGatewayId());
            if ($zone->getIsActive())
                array_push($this->servers, array($zone->getName(), $zone->getUrl(), $zone->getNotFoundString()));
        }
    }
}
